/*  
 * i-OSGi - Tunable Bundle Isolation for OSGi
 * Copyright (C) 2011  Sven Schulz
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.iosgi.ie.os;

import java.io.IOException;
import java.net.InterfaceAddress;
import java.net.SocketException;
import java.net.URI;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.felix.ipojo.annotations.Component;
import org.apache.felix.ipojo.annotations.Provides;
import org.apache.felix.ipojo.annotations.Requires;
import org.apache.felix.ipojo.annotations.ServiceProperty;
import org.iosgi.Constants;
import org.iosgi.IsolationEnvironment;
import org.iosgi.impl.EnvironmentIDs;
import org.iosgi.outpost.util.ipr.MacAddress;
import org.iosgi.util.Networking;
import org.osgi.framework.BundleContext;
import org.virtualbox_4_0.IMachine;
import org.virtualbox_4_0.IProgress;
import org.virtualbox_4_0.ISession;
import org.virtualbox_4_0.IVirtualBox;
import org.virtualbox_4_0.VirtualBoxManager;

/**
 * @author Sven Schulz
 */
@Component(immediate = true)
@Provides(specifications = { IsolationEnvironment.class })
public class OperatingSystemIE implements IsolationEnvironment {

	private static ExecutorService EXEC_SVC = Executors
			.newSingleThreadExecutor();

	@ServiceProperty(name = "environment.id")
	private URI id;

	@SuppressWarnings("unused")
	@ServiceProperty(name = Constants.R_OSGI_REGISTRATION)
	private boolean publishRemotely = Boolean.TRUE;

	@SuppressWarnings("unused")
	@ServiceProperty(name = Constants.LEVEL)
	private int level = 1;

	@Requires
	private VirtualBox virtualBox;

	private BundleContext context;

	private OperatingSystemIE(BundleContext context) throws SocketException {
		this.context = context;
		id = EnvironmentIDs.getEnvironmentId(0);
	}

	@Override
	public URI getId() {
		return id;
	}

	@Override
	public synchronized void destroy() throws IOException {
		URL url = virtualBox.getManagerUrl();
		final VirtualBoxManager vboxMgr = VirtualBoxManager
				.createInstance(null);
		vboxMgr.connect(url.toString(), "user", "pwd");
		MacAddress mac = null;
		for (Map.Entry<MacAddress, InterfaceAddress> e : MacAddress
				.getAddresses().entrySet()) {
			if (e.getValue().getAddress()
					.equals(Networking.getPrimaryAddress())) {
				mac = e.getKey();
			}
		}
		IVirtualBox vbox = vboxMgr.getVBox();
		for (final IMachine m : vbox.getMachines()) {
			MacAddress mmac = new MacAddress(m.getNetworkAdapter(0L)
					.getMACAddress());
			if (mmac.equals(mac)) {
				EXEC_SVC.submit(new Callable<Void>() {
					@Override
					public Void call() throws Exception {
						synchronized (OperatingSystemIE.this) {
							context.getBundle(0).stop();
							shutdownVM(vboxMgr, m);
						}
						return null;
					}
				});
				return;
			}
		}
	}

	private void shutdownVM(VirtualBoxManager vboxMgr, IMachine m)
			throws IOException {
		ISession s = null;
		try {
			s = vboxMgr.openMachineSession(m);
		} catch (Exception e) {
			throw new IOException(e);
		}
		IProgress p = s.getConsole().powerDown();
		p.waitForCompletion(-1);
		vboxMgr.closeMachineSession(s);
	}
}